home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / programming / c / cc.lha / cc.c < prev    next >
C/C++ Source or Header  |  1994-10-12  |  20KB  |  993 lines

  1. /**
  2. ***  cc.c   Unix compatible frontend for Amiga's C compilers
  3. ***
  4. ***  This program is free software; you can redistribute it and/or modify
  5. ***  it under the terms of the GNU General Public License as published by
  6. ***  the Free Software Foundation; either version 2 of the License, or
  7. ***  (at your option) any later version.
  8. ***
  9. ***  This program is distributed in the hope that it will be useful,
  10. ***  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ***  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. ***  GNU General Public License for more details.
  13. ***
  14. ***  You should have received a copy of the GNU General Public License
  15. ***  along with this program; if not, write to the Free Software
  16. ***  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ***
  18. ***
  19. ***  Compiler:    dcc V3.01
  20. ***
  21. ***  Computer:    Amiga 1200
  22. ***
  23. ***  Author:    Jochen Wiedmann
  24. ***        Am Eisteich 9
  25. ***        72555 Metzingen
  26. ***        Germany
  27. ***
  28. ***        Phone: (49)7123 / 14881
  29. ***        Internet: wiedmann@zdv.uni-tuebingen.de
  30. ***
  31. ***
  32. ***
  33. ***  This is a Unix compatible frontend for gcc, SAS/C and Dice. In fact,
  34. ***  it does nothing than else than calling the appropriate frontends
  35. ***  with the appropriate options.
  36. ***
  37. ***  Supported options are:
  38. ***
  39. ***    -v        Verbose (try it :-)
  40. ***    -c        Don't link
  41. ***    -a        Compile only, don't assemble
  42. ***    -E        Run preprocessor only
  43. ***    -I<dir>     Look for include files in directory <dir>
  44. ***    -L<dir>     Look for libraries in directory <dir>
  45. ***    -o<file>    Set the name of the created file; it is recommended
  46. ***            to use this as the respective frontends might behave
  47. ***            different in selecting default names.
  48. ***    -D<symbol>  Defines preprocessor symbol; use -Dsymbol=var for
  49. ***            specific values.
  50. ***    -U<symbol>  Undefine the preprocessor symbol <symbol>.
  51. ***    -l<lib>     Link with library <lib>.
  52. ***    -g        Turn debugging on.
  53. ***    -O        Optimize
  54. ***
  55. **/
  56.  
  57. /**
  58. ***  Version string
  59. **/
  60. #define VERSION        1
  61. #define REVISION     1
  62. #define DATE    "11.10.94"
  63. #define VERS    "cc 1.1"
  64. #define VSTRING "cc 1.1 (11.10.94)"
  65. #define VERSTAG "\0$VER: cc 1.1 (11.10.94)"
  66. char Version[] = VSTRING;
  67.  
  68. char AmigaVersion[] = VERSTAG;
  69.  
  70.  
  71.  
  72.  
  73. /**
  74. ***  Include files
  75. **/
  76. #include <stdlib.h>
  77. #include <string.h>
  78. #include <stdio.h>
  79. #include <stdarg.h>
  80. #include <exec/lists.h>
  81. #include <exec/nodes.h>
  82. #include <clib/alib_protos.h>
  83. #include <clib/exec_protos.h>
  84. #include <clib/dos_protos.h>
  85. #include <pragmas/exec_pragmas.h>
  86. #include <pragmas/dos_pragmas.h>
  87. extern struct Library *SysBase;
  88. extern struct Library *DOSBase;
  89.  
  90.  
  91.  
  92.  
  93.  
  94. /**
  95. ***  List of options processed by cc:
  96. **/
  97. typedef enum
  98.   {
  99.     OPTION_UNKNOWN,
  100.     OPTION_VERBOSE,
  101.     OPTION_DEFINE,
  102.     OPTION_UNDEFINE,
  103.     OPTION_PREPROCESSOR_ONLY,
  104.     OPTION_ASSEMBLER_ONLY,
  105.     OPTION_NOLINK,
  106.     OPTION_INCLUDEDIR,
  107.     OPTION_LINKDIR,
  108.     OPTION_OPTIMIZE,
  109.     OPTION_DEBUGGING,
  110.     OPTION_LIBRARY,
  111.     OPTION_OUTPUT
  112.   } CompilerOption;
  113.  
  114.  
  115.  
  116.  
  117.  
  118. /**
  119. ***  This structure defines an element in the list of options.
  120. **/
  121. typedef struct
  122.   {
  123.     struct MinNode mn;
  124.     CompilerOption Option;
  125.     char *Arg;
  126.   } CurrentOption;
  127.  
  128.  
  129.  
  130.  
  131.  
  132. /**
  133. ***  Compatibility mode (Default: gcc)
  134. **/
  135. enum
  136.   {
  137.     COMPATIBILITYMODE_GCC,
  138.     COMPATIBILITYMODE_SAS,
  139.     COMPATIBILITYMODE_DICE,
  140.   } CompatibilityMode = COMPATIBILITYMODE_GCC;
  141. char *CompatibilityModeNames[] =
  142.   {
  143.     "-gcc",
  144.     "-sas",
  145.     "-dice"
  146.   };
  147.  
  148.  
  149.  
  150.  
  151. /**
  152. ***  Compiler mode (Default: Everything)
  153. **/
  154. enum
  155.   {
  156.     COMPILERMODE_PREPROCESSOR_ONLY,
  157.     COMPILERMODE_COMPILER_ONLY,
  158.     COMPILERMODE_ASSEMBLER_ONLY,
  159.     COMPILERMODE_EVERYTHING,
  160.   } CompilerMode = COMPILERMODE_EVERYTHING;
  161. char *CompilerModeNames[] =
  162.   {
  163.     "-E",
  164.     "-a",
  165.     "-c"
  166.   };
  167.  
  168.  
  169.  
  170.  
  171. /**
  172. ***  These lists are used to hold the current options.
  173. **/
  174. struct List OptionList;
  175.  
  176.  
  177.  
  178.  
  179.  
  180. /**
  181. ***  Guess, what this function does? :-)
  182. **/
  183. void Usage(void)
  184.  
  185.   {
  186.     printf("%s%s%s", "Usage: cc [options] [files]\n\
  187. \n\
  188. Options known to cc are:\n\
  189. \n\
  190. -v\t\tbe verbose\n\
  191. -o<file>\t\tsend output to <file> (usage is recommended)\n\
  192. -E\t\trun preprocessor only\n\
  193. -a\t\trun preprocessor and compiler only\n\
  194. -c\t\trun preprocessor, compiler and assembler, don't link\n\
  195. -I<dir>\t\tlook for include files in <dir>\n\
  196. -L<dir>\t\took for link libraries in <dir>\n\
  197. -l<lib>\t\tlink with library <lib>\n\
  198. -g\t\tturn debugging on\n\
  199. -O\t\tturn optimization on\n\
  200. -D<sym>\t\tdefine preprocessor symbol\n\
  201. -U<sym>\t\tundefine preprocessor symbol\n\
  202. -h,--help,?\tprint this message\n\
  203. \n\n", Version, "\n\
  204. ©1994  by Jochen Wiedmann, all rights reserved\n\n\
  205. This program is governed by the terms and conditions of the GNU General\n\
  206. Public License. A copy should have come with this distribution. (See the\n\
  207. file COPYING.) In that license it is made clear that you are welcome to\n\
  208. redistribute either verbatim or modified copies of the program and the\n\
  209. documentation under certain conditions. Further you are told that this\n\
  210. program comes with ABSOLUTELY NO WARRANTY!\n\n\n");
  211.     exit(5);
  212.   }
  213.  
  214.  
  215.  
  216.  
  217.  
  218. /**
  219. ***  This functions adds a new option to the list of options.
  220. **/
  221. void AddOption(CompilerOption co, char *arg)
  222.  
  223.   {
  224.     CurrentOption *cu;
  225.  
  226.     if (!(cu = malloc(sizeof(*cu))))
  227.       {
  228.     fprintf(stderr, "Out of memory!");
  229.     exit(20);
  230.       }
  231.     cu->Option = co;
  232.     cu->Arg = arg;
  233.     AddTail(&OptionList, (struct Node *) cu);
  234.   }
  235.  
  236.  
  237.  
  238.  
  239.  
  240. /**
  241. ***  This function handles options which may be splitted into two
  242. ***  arguments or not, like -I <dir> or -I<dir>.
  243. **/
  244. void AddOptionArg(CompilerOption co,
  245.           int *i,
  246.           int argc,
  247.           char *argv[])
  248.  
  249.   {
  250.     char *arg = &argv[*i][2];
  251.  
  252.     if (!*arg)
  253.       {
  254.     if (++(*i) >= argc)
  255.       {
  256.         fprintf(stderr, "%s: Missing argument: %s\n", argv[--(*i)]);
  257.         exit(20);
  258.       }
  259.     arg = argv[*i];
  260.       }
  261.  
  262.     AddOption(co, arg);
  263.   }
  264.  
  265.  
  266.  
  267.  
  268.  
  269. /**
  270. ***  This function is used to set the compatibility mode.
  271. **/
  272. void SetCompatibilityMode(int mode, int *set)
  273.  
  274.   {
  275.     if (*set)
  276.       {
  277.     fprintf(stderr, "cc, warning: %s overwrites %s\n",
  278.         CompatibilityModeNames[mode],
  279.         CompatibilityModeNames[CompatibilityMode]);
  280.     exit(10);
  281.       }
  282.     *set = TRUE;
  283.     CompatibilityMode = mode;
  284.   }
  285.  
  286.  
  287.  
  288.  
  289.  
  290. /**
  291. ***  This function is used to set the compatibility mode.
  292. **/
  293. void SetCompilerMode(int mode, int *set)
  294.  
  295.   {
  296.     if (*set)
  297.       {
  298.     fprintf(stderr, "cc warning: %s overwrites %s\n",
  299.         CompilerModeNames[mode],
  300.         CompilerModeNames[CompilerMode]);
  301.     exit(10);
  302.       }
  303.     *set = TRUE;
  304.     CompilerMode = mode;
  305.   }
  306.  
  307.  
  308.  
  309.  
  310.  
  311. /**
  312. ***  This function is used to build the string that is used to call
  313. ***  the real frontend. It supports strings of any length, thus it
  314. ***  may look somewhat complicated.
  315. **/
  316. void AddToString(char **strptr, char *format, ...)
  317.  
  318.   {
  319.     static char buffer[1024];    /*  Maximal length of *one* argument    */
  320.     static int RealLen;
  321.     static int MaxLen;
  322.     int len;
  323.     va_list args;
  324.  
  325.     va_start(args, format);
  326.     vsprintf(buffer, format, args);
  327.     len = strlen(buffer);
  328.  
  329.     if (!*strptr)
  330.       {
  331.     MaxLen = 0;
  332.       }
  333.  
  334.     if (len + RealLen + 1 > MaxLen)
  335.       {
  336.     /**
  337.     ***  Current buffer not sufficient, allocate a new buffer
  338.     **/
  339.     char *newstr;
  340.  
  341.     if (!(newstr = malloc(MaxLen+1024)))
  342.       {
  343.         fprintf(stderr, "Out of memory!");
  344.         exit(20);
  345.       }
  346.     MaxLen += 1024;
  347.  
  348.     if (*strptr)
  349.       {
  350.         strcpy(newstr, *strptr);
  351.       }
  352.     else
  353.       {
  354.         *newstr = '\0';
  355.         RealLen = 0;
  356.       }
  357.     *strptr = newstr;
  358.       }
  359.  
  360.     strcpy(*strptr + RealLen, buffer);
  361.     RealLen += len;
  362.   }
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369. /**
  370. ***  This function is used to parse the arguments. Options will
  371. ***  be included into OptionList, files in FileList.
  372. **/
  373. void ParseArgs(int argc,
  374.            char *argv[])
  375.  
  376.   {
  377.     int i;
  378.     /**
  379.     ***  These variables are used for checking if arguments repeat.
  380.     ***  Note that we keep them local: This allows, for example,
  381.     ***  to use different settings in the environment and on the
  382.     ***  command line.
  383.     **/
  384.     int CompatibilityModeIsSet = FALSE;
  385.     int CompilerModeIsSet = FALSE;
  386.  
  387.     for (i = 0;  i < argc;  i++)
  388.       {
  389.     char *argvi = argv[i];
  390.  
  391.     if (argvi[0] == '-')
  392.       {
  393.         /**
  394.         ***  Assume this to be a compiler option.
  395.         **/
  396.  
  397.         switch(argvi[1])
  398.           {
  399.         case '-':
  400.           if (strcmp(argvi, "--help") == 0)
  401.             {
  402.               Usage();
  403.             }
  404.           AddOption(OPTION_UNKNOWN, argvi);
  405.           break;
  406.         case 'D':
  407.           AddOptionArg(OPTION_DEFINE, &i, argc, argv);
  408.           break;
  409.         case 'E':
  410.           switch(argvi[2])
  411.             {
  412.               case '\0':
  413.             SetCompilerMode(COMPILERMODE_PREPROCESSOR_ONLY,
  414.                     &CompilerModeIsSet);
  415.             break;
  416.               default:
  417.             AddOption(OPTION_UNKNOWN, argvi);
  418.             break;
  419.             }
  420.           break;
  421.         case 'I':
  422.           AddOptionArg(OPTION_INCLUDEDIR, &i, argc, argv);
  423.           break;
  424.         case 'L':
  425.           AddOptionArg(OPTION_LINKDIR, &i, argc, argv);
  426.           break;
  427.         case 'O':
  428.           AddOption(OPTION_OPTIMIZE, &argvi[2]);
  429.           break;
  430.         case 'U':
  431.           AddOptionArg(OPTION_UNDEFINE, &i, argc, argv);
  432.           break;
  433.         case 'a':
  434.           switch(argvi[2])
  435.             {
  436.               case '\0':
  437.             SetCompilerMode(COMPILERMODE_COMPILER_ONLY,
  438.                     &CompilerModeIsSet);
  439.             break;
  440.               default:
  441.             AddOption(OPTION_UNKNOWN, argvi);
  442.             break;
  443.             }
  444.           break;
  445.         case 'c':
  446.           switch(argvi[2])
  447.             {
  448.               case '\0':
  449.             SetCompilerMode(COMPILERMODE_ASSEMBLER_ONLY,
  450.                     &CompilerModeIsSet);
  451.             break;
  452.               default:
  453.             AddOption(OPTION_UNKNOWN, argvi);
  454.             break;
  455.             }
  456.           break;
  457.         case 'd':
  458.           if (strcmp(argvi,
  459.                  CompatibilityModeNames[COMPATIBILITYMODE_DICE]) == 0)
  460.             {
  461.               SetCompatibilityMode(COMPATIBILITYMODE_DICE,
  462.                        &CompatibilityModeIsSet);
  463.             }
  464.           else
  465.             {
  466.               AddOption(OPTION_UNKNOWN, argvi);
  467.             }
  468.           break;
  469.         case 'g':
  470.           switch(argvi[2])
  471.             {
  472.               case '\0':
  473.             AddOption(OPTION_DEBUGGING, argvi);
  474.             break;
  475.               default:
  476.             if (strcmp(argvi,
  477.                    CompatibilityModeNames[COMPATIBILITYMODE_GCC]) == 0)
  478.               {
  479.                 SetCompatibilityMode(COMPATIBILITYMODE_GCC,
  480.                          &CompatibilityModeIsSet);
  481.               }
  482.             else
  483.               {
  484.                 AddOption(OPTION_UNKNOWN, argvi);
  485.               }
  486.             break;
  487.             }
  488.           break;
  489.         case 'h':
  490.           switch(argvi[2])
  491.             {
  492.               case '\0':
  493.             Usage();
  494.               default:
  495.             AddOption(OPTION_UNKNOWN, argvi);
  496.             break;
  497.             }
  498.           break;
  499.         case 'l':
  500.           AddOptionArg(OPTION_LIBRARY, &i, argc, argv);
  501.           break;
  502.         case 'o':
  503.           AddOptionArg(OPTION_OUTPUT, &i, argc, argv);
  504.           break;
  505.         case 's':
  506.           if (strcmp(argvi,
  507.                  CompatibilityModeNames[COMPATIBILITYMODE_SAS]) == 0)
  508.             {
  509.               SetCompatibilityMode(COMPATIBILITYMODE_SAS,
  510.                        &CompatibilityModeIsSet);
  511.             }
  512.           else
  513.             {
  514.               AddOption(OPTION_UNKNOWN, argvi);
  515.             }
  516.           break;
  517.         case 'v':
  518.           switch(argvi[2])
  519.             {
  520.               case '\0':
  521.             AddOption(OPTION_VERBOSE, argvi);
  522.             break;
  523.               default:
  524.             AddOption(OPTION_UNKNOWN, argvi);
  525.             break;
  526.             }
  527.             break;
  528.         default:
  529.           AddOption(OPTION_UNKNOWN, argvi);
  530.           break;
  531.           }
  532.       }
  533.     else if (strcmp(argvi, "?") == 0)
  534.       {
  535.         Usage();
  536.       }
  537.     else
  538.       {
  539.         AddOption(OPTION_UNKNOWN, argvi);
  540.       }
  541.       }
  542.   }
  543.  
  544.  
  545.  
  546.  
  547.  
  548. /**
  549. ***  This function calls gcc as a frontend.
  550. **/
  551. int CompileGcc(void)
  552.  
  553.   {
  554.     CurrentOption *co;
  555.     char *CompileString = NULL;
  556.     int Verbose = FALSE;
  557.  
  558.     AddToString(&CompileString, "gcc");
  559.  
  560.     for (co = (CurrentOption *) OptionList.lh_Head;
  561.      co->mn.mln_Succ != NULL;
  562.      co = (CurrentOption *) co->mn.mln_Succ)
  563.       {
  564.     switch (co->Option)
  565.       {
  566.         case OPTION_UNKNOWN:
  567.           AddToString(&CompileString, " \"%s\"", co->Arg);
  568.           break;
  569.         case OPTION_VERBOSE:
  570.           AddToString(&CompileString, " -v");
  571.           Verbose = TRUE;
  572.           break;
  573.         case OPTION_DEFINE:
  574.           AddToString(&CompileString, " \"-D%s\"", co->Arg);
  575.           break;
  576.         case OPTION_UNDEFINE:
  577.           AddToString(&CompileString, " \"-U%s\"", co->Arg);
  578.           break;
  579.         case OPTION_PREPROCESSOR_ONLY:
  580.           AddToString(&CompileString, " -E");
  581.           break;
  582.         case OPTION_ASSEMBLER_ONLY:
  583.           AddToString(&CompileString, " -a");
  584.           break;
  585.         case OPTION_NOLINK:
  586.           AddToString(&CompileString, " -c");
  587.           break;
  588.         case OPTION_INCLUDEDIR:
  589.           AddToString(&CompileString, " \"-I%s\"", co->Arg);
  590.           break;
  591.         case OPTION_LINKDIR:
  592.           AddToString(&CompileString, " \"-L%s\"", co->Arg);
  593.           break;
  594.         case OPTION_OPTIMIZE:
  595.           AddToString(&CompileString, " \"-O%s\"", co->Arg);
  596.           break;
  597.         case OPTION_DEBUGGING:
  598.           AddToString(&CompileString, " -g");
  599.           break;
  600.         case OPTION_LIBRARY:
  601.           AddToString(&CompileString, " \"-l%s\"", co->Arg);
  602.           break;
  603.         case OPTION_OUTPUT:
  604.           AddToString(&CompileString, " -o \"%s\"", co->Arg);
  605.           break;
  606.       }
  607.       }
  608.  
  609.     AddToString(&CompileString, "\n");
  610.     if (Verbose)
  611.       {
  612.     printf("%s\n%s", Version, CompileString);
  613.       }
  614.  
  615.     return(system(CompileString));
  616.   }
  617.  
  618.  
  619.  
  620.  
  621.  
  622. /**
  623. ***  This function calls SAS/C as a frontend.
  624. **/
  625. int CompileSAS(void)
  626.  
  627.   {
  628.     CurrentOption *co;
  629.     char *CompileString = NULL;
  630.     int Verbose = FALSE;
  631.     char *OptionOutput = NULL;
  632.  
  633.     AddToString(&CompileString, "sc");
  634.  
  635.     for (co = (CurrentOption *) OptionList.lh_Head;
  636.      co->mn.mln_Succ != NULL;
  637.      co = (CurrentOption *) co->mn.mln_Succ)
  638.       {
  639.     switch (co->Option)
  640.       {
  641.         case OPTION_UNKNOWN:
  642.           AddToString(&CompileString, " \"%s\"", co->Arg);
  643.           break;
  644.         case OPTION_VERBOSE:
  645.           AddToString(&CompileString, " VERBOSE");
  646.           Verbose = TRUE;
  647.           break;
  648.         case OPTION_DEFINE:
  649.           AddToString(&CompileString, " DEF \"%s\"", co->Arg);
  650.           break;
  651.         case OPTION_UNDEFINE:    /*  Not supported   */
  652.           break;
  653.         case OPTION_INCLUDEDIR:
  654.           AddToString(&CompileString, " IDIR\"%s\"", co->Arg);
  655.           break;
  656.         case OPTION_LINKDIR:    /*  Not supported   */
  657.           break;
  658.         case OPTION_OPTIMIZE:
  659.           AddToString(&CompileString, " OPTIMIZE");
  660.           break;
  661.         case OPTION_DEBUGGING:
  662.           AddToString(&CompileString, " DEBUG FULLFLUSH");
  663.           break;
  664.         case OPTION_LIBRARY:
  665.           AddToString(&CompileString, " LIBRARY \"%s.lib\"", co->Arg);
  666.           break;
  667.         case OPTION_OUTPUT:
  668.           OptionOutput = co->Arg;
  669.           break;
  670.       }
  671.       }
  672.  
  673.     switch(CompilerMode)
  674.       {
  675.     case COMPILERMODE_PREPROCESSOR_ONLY:
  676.       AddToString(&CompileString, " PPONLY");
  677.     case COMPILERMODE_ASSEMBLER_ONLY:
  678.       if (OptionOutput)
  679.         {
  680.           AddToString(&CompileString, " OBJNAME \"%s\"", OptionOutput);
  681.         }
  682.       break;
  683.     case COMPILERMODE_COMPILER_ONLY:
  684.       if (!OptionOutput)
  685.         {
  686.           OptionOutput = "*";
  687.         }
  688.       AddToString(&CompileString, " \"DISASM=%s\"", OptionOutput);
  689.       break;
  690.     case COMPILERMODE_EVERYTHING:
  691.       if (OptionOutput)
  692.         {
  693.           AddToString(&CompileString, " PNAME \"%s\"", OptionOutput);
  694.         }
  695.       AddToString(&CompileString, " LINK");
  696.       break;
  697.       }
  698.  
  699.     AddToString(&CompileString, "\n");
  700.     if (Verbose)
  701.       {
  702.     printf("%s\n%s", Version, CompileString);
  703.       }
  704.  
  705.     return(system(CompileString));
  706.   }
  707.  
  708.  
  709.  
  710.  
  711.  
  712.  
  713. /**
  714. ***  This function calls Dice as a frontend.
  715. **/
  716. int CompileDice(void)
  717.  
  718.   {
  719.     CurrentOption *co;
  720.     char *CompileString = NULL;
  721.     int Verbose = FALSE;
  722.  
  723.     switch(CompilerMode)
  724.       {
  725.     case COMPILERMODE_PREPROCESSOR_ONLY:
  726.       AddToString(&CompileString, "dcpp");
  727.       break;
  728.     case COMPILERMODE_COMPILER_ONLY:
  729.       AddToString(&CompileString, "dcc -a");
  730.       break;
  731.     case COMPILERMODE_ASSEMBLER_ONLY:
  732.       AddToString(&CompileString, "dcc -c");
  733.       break;
  734.     default:
  735.       AddToString(&CompileString, "dcc");
  736.       break;
  737.       }
  738.  
  739.     for (co = (CurrentOption *) OptionList.lh_Head;
  740.      co->mn.mln_Succ != NULL;
  741.      co = (CurrentOption *) co->mn.mln_Succ)
  742.       {
  743.     switch (co->Option)
  744.       {
  745.         case OPTION_UNKNOWN:
  746.           AddToString(&CompileString, " \"%s\"", co->Arg);
  747.           break;
  748.         case OPTION_VERBOSE:
  749.           if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
  750.         {
  751.           AddToString(&CompileString, " -v", co->Arg);
  752.         }
  753.           Verbose = TRUE;
  754.           break;
  755.         case OPTION_DEFINE:
  756.           AddToString(&CompileString, " \"-D%s\"", co->Arg);
  757.           break;
  758.         case OPTION_UNDEFINE:        /*    Not supported    */
  759.           break;
  760.         case OPTION_INCLUDEDIR:
  761.           AddToString(&CompileString, " \"-I%s\"", co->Arg);
  762.           break;
  763.         case OPTION_LINKDIR:
  764.           if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
  765.         {
  766.           AddToString(&CompileString, " \"-L%s\"", co->Arg);
  767.         }
  768.           break;
  769.         case OPTION_OPTIMIZE:        /*    Not suported    */
  770.           break;
  771.         case OPTION_DEBUGGING:
  772.           if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
  773.         {
  774.           AddToString(&CompileString, " -s -d1");
  775.         }
  776.           break;
  777.         case OPTION_LIBRARY:
  778.           if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
  779.         {
  780.           AddToString(&CompileString, " \"-l%s\"", co->Arg);
  781.         }
  782.           break;
  783.         case OPTION_OUTPUT:
  784.           AddToString(&CompileString, " -o \"%s\"", co->Arg);
  785.           break;
  786.       }
  787.       }
  788.  
  789.     AddToString(&CompileString, "\n");
  790.     if (Verbose)
  791.       {
  792.     printf("%s\n%s", Version, CompileString);
  793.       }
  794.  
  795.     return(system(CompileString));
  796.   }
  797.  
  798.  
  799.  
  800.  
  801.  
  802. /**
  803. ***  This function is used to split a string into arguments.
  804. ***  It returns an array similar to argv.
  805. ***
  806. ***  I don't like doing things for myself, but as far as I
  807. ***  can see neither SAS nor Dice offer a possibility of
  808. ***  doing this.
  809. ***
  810. ***  Inputs: argstr - the string to split into arguments,
  811. ***        for example an AmigaDOS command line;
  812. ***        may contain arguments like
  813. ***            "This is one argument"
  814. ***        or
  815. ***            "Note the "" inside this argument"
  816. ***        where the double quotation mark will be
  817. ***        changed into one.
  818. ***        argc - pointer to an int where to store the
  819. ***        number of arguments found in argstr
  820. ***
  821. ***  Result: an NULL terminated array of pointers to the
  822. ***        arguments or NULL; note that the pointers go
  823. ***        into argstr and argstr will be modified.
  824. **/
  825. char **SplitArgs(char *argstr, int *argcptr)
  826.  
  827.   {
  828.     int argc;
  829.     char *argptr;
  830.     char **argv;
  831.     char **argvptr;
  832.  
  833.     /**
  834.     ***  Parse the string for the first time counting
  835.     ***  the number of arguments.
  836.     **/
  837.     argptr = argstr;
  838.     argc = 0;
  839.     for(;;)
  840.       {
  841.     /**
  842.     ***  Skip blanks
  843.     **/
  844.     while (*argptr == ' '  ||  *argptr == '\t')
  845.       {
  846.         ++argptr;
  847.       }
  848.  
  849.     if (*argptr == '\0'  ||  *argptr == '\n'  ||  *argptr == '\r')
  850.       {
  851.         break;
  852.       }
  853.  
  854.     ++argc;
  855.  
  856.     if (*argptr == '\"')
  857.       {
  858.         do
  859.           {
  860.         ++argptr;
  861.         if (*argptr == '\"')
  862.           {
  863.             if (*(argptr+1) == '\"')
  864.               {
  865.             ++argptr;
  866.               }
  867.             else
  868.               {
  869.             break;
  870.               }
  871.           }
  872.           }
  873.         while (*argptr != '\0'  &&  *argptr != '\r'  &&  *argptr != '\n');
  874.       }
  875.     else
  876.       {
  877.         while (*argptr != '\0'  &&  *argptr != '\r'  &&  *argptr != '\n'  &&
  878.            *argptr != '\t'  &&  *argptr != ' ')
  879.           {
  880.         ++argptr;
  881.           }
  882.       }
  883.     {
  884.       char c;
  885.  
  886.       c = *argptr;
  887.       *(argptr++) = '\0';
  888.  
  889.       if (c == '\0'  ||  c == '\r'  ||  c == '\n')
  890.         {
  891.           break;
  892.         }
  893.     }
  894.       }
  895.  
  896.     *argcptr = argc;
  897.     if (!(argv = malloc(sizeof(char *) * (argc+1))))
  898.       {
  899.     return(NULL);
  900.       }
  901.  
  902.     /**
  903.     ***  Parse the string a second time
  904.     **/
  905.     for (argvptr = argv, argptr = argstr;  argc > 0;  --argc, ++argvptr)
  906.       {
  907.     int inside;
  908.  
  909.     while (*argptr == ' '  ||  *argptr == '\t')
  910.       {
  911.         ++argptr;
  912.       }
  913.  
  914.     if (*argptr == '\"')
  915.       {
  916.         ++argptr;
  917.         inside = TRUE;
  918.       }
  919.     else
  920.       {
  921.         inside = FALSE;
  922.       }
  923.     *argvptr = argptr;
  924.  
  925.     while (*argptr)
  926.       {
  927.         if (*argptr == '\"'  &&  inside)
  928.           {
  929.         char *ptr;
  930.         char *oldptr;
  931.  
  932.         /**
  933.         ***  Found a "", remove the second ".
  934.         **/
  935.         for(ptr = argptr++, oldptr = *argvptr;
  936.             ptr >= oldptr;  --ptr)
  937.           {
  938.             *(ptr+1) = *ptr;
  939.           }
  940.         *argvptr = oldptr+1;
  941.           }
  942.         ++argptr;
  943.       }
  944.     ++argptr;
  945.       }
  946.     *argvptr = NULL;
  947.  
  948.     return(argv);
  949.   }
  950.  
  951.  
  952.  
  953.  
  954.  
  955. /**
  956. ***  Finally main().
  957. **/
  958. int main(int argc, char *argv[])
  959.  
  960.   {
  961.     char *cflags;
  962.  
  963.     NewList(&OptionList);
  964.  
  965.     if ((cflags = getenv("CCOPT")))
  966.       {
  967.     int envargc;
  968.     char **envargv;
  969.  
  970.     if (!(envargv = SplitArgs(cflags, &envargc)))
  971.       {
  972.         fprintf(stderr, "Out of memory!\n");
  973.         exit(20);
  974.       }
  975.     ParseArgs(envargc, envargv);
  976.       }
  977.  
  978.     ParseArgs(argc-1, argv+1);
  979.  
  980.     switch(CompatibilityMode)
  981.       {
  982.     case COMPATIBILITYMODE_GCC:
  983.       CompileGcc();
  984.       break;
  985.     case COMPATIBILITYMODE_SAS:
  986.       CompileSAS();
  987.       break;
  988.     case COMPATIBILITYMODE_DICE:
  989.       CompileDice();
  990.       break;
  991.       }
  992.   }
  993.